package fina2.dcs.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.NoSuchProviderException;
import javax.mail.Provider;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

import org.apache.log4j.Logger;

import fina2.dcs.mail.manager.MailPropsKey;
import fina2.dcs.mail.manager.MailUser;
import fina2.dcs.mail.util.MailUtil;

@SuppressWarnings("serial")
public class MailSenderSMTP implements MailSenderBase {
	private Logger log = Logger.getLogger(getClass());
	private Provider smtpProvider = new Provider(Provider.Type.TRANSPORT, "smtp", "com.sun.mail.smtp.SMTPTransport", "Sun Microsystems, Inc", "1.4.4");
	private Provider smtpSSLProvider = new Provider(Provider.Type.TRANSPORT, "smtps", "com.sun.mail.smtp.SMTPSSLTransport", "Sun Microsystems, Inc", "1.4.4");

	private MailUser mailUser;

	private final String folderName = "INBOX";

	private String host;
	private int port;
	private boolean isSSL;
	private boolean isTSL;

	private Transport transport;

	private Session session;

	public MailSenderSMTP(MailUser mailUser) {
		this.mailUser = mailUser;

		initArgs();

		Properties properties = generateProperties();

		URLName urlName = createURLName();

		Authenticator auth = new MailUtil.MyAuthenticator(mailUser.getUser(), mailUser.getPassword());

		session = Session.getDefaultInstance(properties, auth);
		// session.setDebug(true);

		try {
			if (isSSL) {
				session.setProvider(smtpSSLProvider);
				transport = session.getTransport(urlName);
			} else {
				session.setProvider(smtpProvider);
				transport = session.getTransport(urlName);
			}

		} catch (NoSuchProviderException e) {
			log.error(e.getMessage(), e);
		}
	}

	@Override
	public void connect() {
		try {
			log.info("Start Connection (SMTP).");
			transport.connect(host, port, mailUser.getUser(), mailUser.getPassword());
			log.info("Connected MailSender(SMTP).");
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
		}
	}

	@Override
	public void send(String messageText, String subject, String[] cc, String[] bcc, String... to) throws Exception {
		MimeMessage message = new MimeMessage(session);
		message.setContent(messageText, "text/html; charset=UTF-8");
		message.setSubject(subject);

		message.setFrom(new InternetAddress(mailUser.getMailAddress()));

		InternetAddress[] addressesTO = new InternetAddress[to.length];
		for (int i = 0; i < addressesTO.length; i++) {
			addressesTO[i] = new InternetAddress(to[i]);
		}

		message.addRecipients(RecipientType.TO, addressesTO);

		InternetAddress[] addressesCC = null;
		if (cc != null) {
			addressesCC = new InternetAddress[cc.length];
			for (int i = 0; i < addressesCC.length; i++) {
				String ccString = cc[i];
				if (!ccString.equals("")) {
					addressesCC[i] = new InternetAddress(ccString);
				}
			}
			message.addRecipients(RecipientType.CC, addressesCC);
		}

		InternetAddress[] addressesBCC = null;
		if (bcc != null) {
			addressesBCC = new InternetAddress[bcc.length];
			for (int i = 0; i < addressesBCC.length; i++) {
				String bccString = bcc[i];
				if (!bccString.equals("")) {
					addressesBCC[i] = new InternetAddress(bccString);
				}
			}
			message.addRecipients(RecipientType.BCC, addressesBCC);
		}

		message.saveChanges();

		transport.sendMessage(message, addressesTO);

		if (addressesCC != null) {
			transport.sendMessage(message, addressesCC);
		}

		if (addressesBCC != null) {
			transport.sendMessage(message, addressesBCC);
		}
	}

	@Override
	public boolean isConected() {
		return transport.isConnected();
	}

	@Override
	public void close() {
		try {
			if (transport != null && transport.isConnected()) {
				transport.close();
				log.info("Close MailSender Connection (SMTP).");
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
		}
	}

	private URLName createURLName() {
		String protocol = "smtp";
		if (isSSL) {
			protocol = "smtps";
		}
		return new URLName(protocol, host, port, folderName, mailUser.getUser(), mailUser.getPassword());
	}

	private void initArgs() {
		host = MailUtil.getProperty(MailPropsKey.MAIL_SMTP_HOST, mailUser.getProperties());
		port = Integer.parseInt(MailUtil.getProperty(MailPropsKey.MAIL_SMTP_PORT, mailUser.getProperties()));
		isSSL = Boolean.parseBoolean(MailUtil.getProperty(MailPropsKey.MAIL_SMTP_SSL_ENABLE, mailUser.getProperties()));
		isTSL = Boolean.parseBoolean(MailUtil.getProperty(MailPropsKey.MAIL_SMTP_STARTTSL_ENABLE, mailUser.getProperties()));
	}

	private Properties generateProperties() {
		Properties properties = new Properties();
		properties.put(MailPropsKey.MAIL_SMTP_HOST, host);
		properties.put(MailPropsKey.MAIL_SMTP_PORT, port);
		properties.put(MailPropsKey.MAIL_SMTP_CONNECTION_TIMEUT, MailUtil.getProperty(MailPropsKey.MAIL_IMAP_CONNECTION_TIMEUT, mailUser.getProperties()));
		properties.put(MailPropsKey.MAIL_SMTP_SSL_ENABLE, isSSL);
		properties.put(MailPropsKey.MAIL_SMTP_STARTTSL_ENABLE, isTSL);

		properties.put("mail.smtp.auth", "true");

		if (isSSL) {
			properties.put("mail.smtp.socketFactory.port", port);
			properties.put("mail.smtp.socketFactory.fallback", "false");
			properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		} else {
			properties.put("mail.smtp.ssl.trust", host);
			properties.setProperty("mail.smtp.auth.plain.disable", "true");
		}
		return properties;
	}

}
